package httpHandler

import (
	"crypto/md5"
	"encoding/hex"
	"fmt"
	baseHttp "gitee.com/zaiqiang231/go-base-app/base_app/http"
	baseLog "gitee.com/zaiqiang231/go-base-app/base_app/log"
	"gitee.com/zaiqiang231/zcamp-service-file/app/config"
	"github.com/gin-gonic/gin"
	"github.com/minio/minio-go/v7"
	"github.com/minio/minio-go/v7/pkg/credentials"
	"image"
	_ "image/gif"
	_ "image/jpeg"
	_ "image/png"
	"io"
	"log"
	"mime"
	"net/http"
	"path"
	"sync"
)

var (
	gMinioClient *minio.Client
	onceCache    sync.Once
	bucketName   = "zcamp-picture"
)

func GetMinioClient(c *gin.Context) *minio.Client {
	onceCache.Do(func() {
		gMinioClient = CreateMinioClient()
		// 创建这个bucket
		err := gMinioClient.MakeBucket(c, bucketName, minio.MakeBucketOptions{})
		if err != nil {
			// 检测这个bucket是否已经存在
			exists, errBucketExists := gMinioClient.BucketExists(c, bucketName)
			if errBucketExists == nil && exists {
				log.Printf("We already own %s\n", bucketName)
			} else {
				log.Printf(err.Error())
			}
		} else {
			log.Printf("Successfully created %s\n", bucketName)
		}

		//修改bucket 公开
		policy := fmt.Sprintf("{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:GetBucketLocation\",\"s3:ListBucket\",\"s3:ListBucketMultipartUploads\"],\"Resource\":[\"arn:aws:s3:::%s\"]},{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:DeleteObject\",\"s3:GetObject\",\"s3:ListMultipartUploadParts\",\"s3:PutObject\",\"s3:AbortMultipartUpload\"],\"Resource\":[\"arn:aws:s3:::%s/*\"]}]}",
			bucketName, bucketName)
		err = gMinioClient.SetBucketPolicy(c, bucketName, policy)
		if err != nil {
			log.Printf("SetBucketPolicy  %s\n", err.Error())
		}
	})
	return gMinioClient
}

func CreateMinioClient() *minio.Client {
	// 基本的配置信息
	endpoint := config.GlobalAppConfig.MinioConfig.Endpoint
	accessKeyID := config.GlobalAppConfig.MinioConfig.AccessKeyID
	secretAccessKey := config.GlobalAppConfig.MinioConfig.SecretAccessKey
	// 初始化一个minio客户端对象
	minioClient, err := minio.New(endpoint, &minio.Options{
		Creds: credentials.NewStaticV4(accessKeyID, secretAccessKey, ""),
	})
	if err != nil {
		log.Fatalf("初始化MinioClient错误：%s", err.Error())
	}
	return minioClient
}

func UploadFile(c *gin.Context) {
	minioClient := GetMinioClient(c)
	// // 获取文件信息
	file, fileHeader, err := c.Request.FormFile("file")
	if err != nil {
		baseHttp.WriteResponse(c, http.StatusInternalServerError, err.Error(), nil)
		return
	}
	defer file.Close()

	extName := path.Ext(fileHeader.Filename)
	contentType := ""
	if contentType = mime.TypeByExtension(extName); contentType == "" {
		contentType = "application/octet-stream"
	}

	hash := md5.New()
	_, err = io.Copy(hash, file)
	if err != nil {
		baseHttp.WriteResponse(c, http.StatusInternalServerError, err.Error(), nil)
		return
	}
	md5 := hex.EncodeToString(hash.Sum(nil))
	saveFileName := md5 + extName

	_, err = file.Seek(0, 0)
	config, _, err := image.DecodeConfig(file)
	if err != nil {
		baseLog.Infof("UploadFile DecodeConfig  %s\n", err.Error())
	}

	_, err = file.Seek(0, 0)
	if err != nil {
		baseLog.Infof("UploadFile file.Seek  %s\n", err.Error())
	}
	info, err := minioClient.PutObject(c, bucketName, saveFileName, file, fileHeader.Size,
		minio.PutObjectOptions{ContentType: contentType})
	if err != nil {
		baseHttp.WriteResponse(c, http.StatusInternalServerError, err.Error(), nil)
		return
	}
	baseHttp.WriteResponse(c, 0, "success", gin.H{
		"originName": fileHeader.Filename,
		"width":      config.Width,
		"height":     config.Height,
		"md5":        md5,
		"saveName":   saveFileName,
		"url":        fmt.Sprintf("/%s/%s", info.Bucket, info.Key),
	})
}
